﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using DetiInteract.Guide.Controls;
using System.Windows.Input;
using System.Globalization;

namespace DetiInteract.Guide
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public sealed partial class MainWindow : Window
	{
		#region Fields

		/// <summary>
		/// Screen size /// </summary>
		public double ScreenSize { get; set; }

		/// <summary>
		/// Calculated width for the Expander's content /// </summary>
		public int ControlWidth { get; set; }

		/// <summary>
		/// Timer used to keep the header labels up to date /// </summary>
		private DispatcherTimer _dateTimer = new DispatcherTimer();

		/// <summary>
		/// Timer used to check for user inactivity /// </summary>
		private DispatcherTimer _inactivityTimer = new DispatcherTimer();

		/// <summary>
		/// Event to signalyze user inactivity /// </summary>
		private event EventHandler SystemIsInactive;

		/// <summary>
		/// Is the system animating it's content? /// </summary>
		private bool _animating = false;

		private List<Expander> _expanderList = new List<Expander>();
		private int _expanderIndex;

		private Control.Controller _controller;

		private HelpWindow _modalWindow;

		#endregion

		#region Constructor
		/// <summary>
		/// Constructor
		/// </summary>
		public MainWindow()
		{
			this.DataContext = this;

			Timeline.DesiredFrameRateProperty.OverrideMetadata(typeof(Timeline), new FrameworkPropertyMetadata { DefaultValue = 20 });

			InitializeComponent();

			Mouse.OverrideCursor = Cursors.None;

			////Logger.Instance.Write(this, "INFO", "MainWindow Initialized");

			// Calculate the control width
			this.ScreenSize = System.Windows.SystemParameters.PrimaryScreenWidth;
			this.ControlWidth = (int)ScreenSize - (dockPanel.Children.Count * 28) - 10 - 10;

			_expanderList.Add(eDocentes);
			_expanderList.Add(eHorarios);
			_expanderList.Add(eMaps);
			_expanderList.Add(eVisita);

			eVisita.Expanded += new RoutedEventHandler(eVisita_Expanded);

			this.SystemIsInactive += new EventHandler(MainWindow_SystemIsInactive);

			// Configure and start the DateTimer
			_dateTimer.Tick += new System.EventHandler(DateTimer_Tick);
			_dateTimer.Interval = new System.TimeSpan(0, 1, 0); // 1 minute
			DateTimer_Tick(_dateTimer, null);
			_dateTimer.Start();

			// Configure and start the InactivityTimer
			_inactivityTimer.Tick += new EventHandler(InactivityTimer_Tick);
			_inactivityTimer.Interval = new System.TimeSpan(0, 2, 0); // 2 minutes
			_inactivityTimer.Start();

			// Set the event handlers to check for End of animation for each page
			ctrlTeachers.AnimationEnd += new EventHandler(lbTeachers_AnimationEnd);
			ctrlTimetables.AnimationEnd += new EventHandler(ctrlTimetables_AnimationEnd);

			try
			{
				_controller = new Control.Controller();
				_controller.Init();

				_controller.Tap += new System.ComponentModel.ProgressChangedEventHandler(controller_Tap);
				_controller.LongPress += new System.ComponentModel.ProgressChangedEventHandler(controller_LongPress);
				_controller.Scroll += new System.ComponentModel.ProgressChangedEventHandler(controller_Scroll);
				_controller.Fling += new System.ComponentModel.ProgressChangedEventHandler(controller_Fling);
				_controller.Rotation += new System.ComponentModel.ProgressChangedEventHandler(controller_Rotation);
				_controller.Connected += new System.ComponentModel.ProgressChangedEventHandler(controller_Connected);
				_controller.Disconnected += new System.ComponentModel.ProgressChangedEventHandler(controller_Disconnected);
				_controller.Zoom += new System.ComponentModel.ProgressChangedEventHandler(_controller_Zoom);

				//Logger.Instance.Write(this, "INFO", "Controller is configured");
			}
			catch (Exception e)
			{
				//Logger.Instance.Write(this, "ERROR", "Controller not configured" + e.ToString());
			}

			_modalWindow = new HelpWindow();
			_modalWindow.Hide();
		}

		void _controller_Zoom(object sender, System.ComponentModel.ProgressChangedEventArgs e)
		{
			//CultureInfo ci = new CultureInfo("en-US");

			//try
			//{
			//    float level = Single.Parse((string)e.UserState, ci);
			//    if (_expanderList[_expanderIndex].Name == "eMaps")
			//    {
			//        if (level >= 0 && level <= 4)
			//            ctrlGoogleMaps.Zoom((level / 2));
			//    }
			//}
			//catch (Exception ex)
			//{
			//    return;
			//}
		}

		void eVisita_Expanded(object sender, RoutedEventArgs e)
		{
			//ctrlViwer3D.Init();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void controller_Disconnected(object sender, System.ComponentModel.ProgressChangedEventArgs e)
		{
			ResetInactivityTimer();

			if (_modalWindow.IsVisible)
			{
				_modalWindow.Hide();
				_modalWindow.ClearItems();
			}

			//Logger.Instance.Write(this, "INFO", "A Bluetooth device has disconnected.");
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void controller_Connected(object sender, System.ComponentModel.ProgressChangedEventArgs e)
		{
			ResetInactivityTimer();

			//Logger.Instance.Write(this, "INFO", "Bluetooth device ("+(string)e.UserState+") connected");
			_modalWindow.ClearItems();

			TextBlock _connectedText = new TextBlock();
			_connectedText.Text = "Ligado a: \t " + (string)e.UserState;
			_connectedText.FontFamily = new FontFamily(new Uri("pack://application:,,,/Fonts/"), "./SegoeWP.ttf#Segoe WP");
			_connectedText.FontSize = 20;
			_modalWindow.AddItem(_connectedText);

			TextBlock _helpText1 = new TextBlock();
			_helpText1.Text = "\nIncline o seu telemóvel para a esquerda ou para a direita para mudar de página. \n"+
							  "Inclinando para a esquerda selecciona a página à esquerda, e inclinando para a direita selecciona a página à direita.\n";
			_helpText1.FontFamily = new FontFamily(new Uri("pack://application:,,,/Fonts/"), "./SegoeWP.ttf#Segoe WP");
			_helpText1.FontSize = 20;
			_modalWindow.AddItem(_helpText1);


			TextBlock _helpText2 = new TextBlock();
			_helpText2.Text = "\nUse o touchscreen do telemóvel para interagir com o conteúdo." +
							  "\nDocentes: Deslize o dedo no ecrã para fazer scroll ao conteúdo" +
							  "\nHorários: Deslize o dedo nas direcções indicadas para mudar de ano ou curso.\n";
			_helpText2.FontFamily = new FontFamily(new Uri("pack://application:,,,/Fonts/"), "./SegoeWP.ttf#Segoe WP");
			_helpText2.FontSize = 20;
			_modalWindow.AddItem(_helpText2);


			TextBlock _helpText3 = new TextBlock();
			_helpText3.Text = "\nFaça um toque longo no ecrã do dispositivo para continuar." +
							  "\nFaça um toque longo de novo para voltar a chamar esta janela.";
			_helpText3.FontFamily = new FontFamily(new Uri("pack://application:,,,/Fonts/"), "./SegoeWP.ttf#Segoe WP");
			_helpText3.FontSize = 20;
			_modalWindow.AddItem(_helpText3);

			_modalWindow.ShowDialog();

		}

		#endregion

		#region UI-Event Handlers
		/// <summary>
		/// Handles and Expanded event for a clicked expander.
		/// Collapses all other expanders in the UI.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		/// 
		private void Expander_Expanded(object sender, RoutedEventArgs e)
		{
			Expander expander = sender as Expander;

			if (expander != null)
			{

				foreach (Expander otherExpander in _expanderList)
				{
					if (otherExpander != expander)
					{
						otherExpander.IsExpanded = false;
					}
					if (otherExpander == expander)
					{
						_expanderIndex = _expanderList.IndexOf(expander);
					}
				}
			}
		}

		#endregion

		#region Timer-related Event Handlers
		/// <summary>
		/// Answers a Tick event for the DateTimer.
		/// Updates the labels in the header with the current time and date.
		/// </summary>
		/// <param name="sender">DateTimer</param>
		/// <param name="e">EventArgs</param>
		void DateTimer_Tick(object sender, EventArgs e)
		{
			lblTime.Content = DateTime.Now.ToString("HH:mm");
			lblDate.Content = DateTime.Now.ToString("D");
		}

		/// <summary>
		/// Resets the Inactivity Timer (user input).
		/// </summary>
		void ResetInactivityTimer()
		{
			//_timeElapsed = 0;
			_inactivityTimer.Stop();
			_animating = false;
			ctrlTeachers.StopAnimation();
			ctrlTimetables.StopAnimation();
			_inactivityTimer.Start();
		}

		/// <summary>
		///  Answers a Tick event for the InactivityTimer.
		///  When system has been inactive for over 2min system enters demonstration mode.
		/// </summary>
		/// <param name="sender">InactivityTimer</param>
		/// <param name="e">EventArgs</param>
		void InactivityTimer_Tick(object sender, EventArgs e)
		{
			//_timeElapsed += 1;


			//if (_timeElapsed > 10.0)
			//{
			if (SystemIsInactive != null) SystemIsInactive(this, new EventArgs());
			//}
			//else
			//{
			//    _animating = false;
			//    ctrlTeachers.StopAnimation();
			//    ctrlTimetables.StopAnimation();
			//}
		}

		#endregion

		#region Animation-Related Event Handlers
		/// <summary>
		/// Handles user inactivity.
		/// Focuses on the first expander and starts its animation.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void MainWindow_SystemIsInactive(object sender, EventArgs e)
		{
			if (_animating == true) return;

			//Logger.Instance.Write(this, "INFO", "User Inactivity - Starting Demo mode." + e.ToString());

			_animating = true;

			if (eDocentes.IsExpanded == false)
				eDocentes.IsExpanded = true;

			ctrlTeachers.StartAnimation();
		}

		/// <summary>
		/// Handles the end of the animation on the Timetables' pane.
		/// Switches to the next pane and starts animation.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void ctrlTimetables_AnimationEnd(object sender, EventArgs e)
		{
			//Logger.Instance.Write(this, "INFO", "Animation finished, restarting");

			eDocentes.IsExpanded = true;
			ctrlTeachers.StartAnimation();
		}

		/// <summary>
		/// Handles the end of the animation on the Teachers' pane.
		/// Switches to the next pane and starts animation.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void lbTeachers_AnimationEnd(object sender, EventArgs e)
		{
			eHorarios.IsExpanded = true;
			ctrlTimetables.StartAnimation();
		}

		#endregion

		#region Controller Event Handlers

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void controller_Scroll(object sender, System.ComponentModel.ProgressChangedEventArgs e)
		{
			// Get scroll data from the EventArgs
			Control.GestureData.ScrollData sd = e.UserState as Control.GestureData.ScrollData;

			ResetInactivityTimer();// = true;


			// Scroll
			//if (activeExpander.Name == "eDocentes")
			if (_expanderList[_expanderIndex].Name == "eDocentes")
			{
				ctrlTeachers.Scroll(sd.X, sd.Y);
				return;
			}

			if (_expanderList[_expanderIndex].Name == "eMaps")
			{
				ctrlGoogleMaps.Scroll(sd.X, sd.Y);
				return;
			}

			//Logger.Instance.Write(this, "USER", "Scrolled in the wrong pane.");
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void controller_LongPress(object sender, System.ComponentModel.ProgressChangedEventArgs e)
		{
			ResetInactivityTimer();
			
			//Logger.Instance.Write(this, "USER", "Got user input: Long press");

			if (_modalWindow.IsVisible)
			{
				_modalWindow.Hide();
				ResetInactivityTimer();
			}
			else
				_modalWindow.Show();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void controller_Tap(object sender, System.ComponentModel.ProgressChangedEventArgs e)
		{
			ResetInactivityTimer();

			//Logger.Instance.Write(this, "USER", "Got user input: Tap");
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void controller_Rotation(object sender, System.ComponentModel.ProgressChangedEventArgs e)
		{
			////Logger.Instance.Write(this, "USER", "Got user input: Rotation");
			Control.GestureData.RotationData rd = e.UserState as Control.GestureData.RotationData;

			ResetInactivityTimer();

			//if (_expanderList[_expanderIndex].Name == "eMaps")
			//{
			//    if (rd.y <= 0 && rd.y >= -90)
			//    {
			//        ctrlGoogleMaps.Tilt(rd.y + 90.0);
			//    }
			//    //return;
			//}

			if (rd.z > 40)
			{
				if (_expanderIndex > 0)
				{
					_expanderIndex -= 1;
					_expanderList[_expanderIndex].IsExpanded = true;

					//Logger.Instance.Write(this, "USER", "Navigate Left");

					return;
				}
			}
			if (rd.z < -40)
			{
				if (_expanderIndex < _expanderList.Count - 1)
				{
					_expanderIndex += 1;
					_expanderList[_expanderIndex].IsExpanded = true;

					//Logger.Instance.Write(this, "User", "Navigate Right");

					return;
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void controller_Fling(object sender, System.ComponentModel.ProgressChangedEventArgs e)
		{
			////Logger.Instance.Write(this, "USER", "Got user input: Fling");
			// Get scroll data from the EventArgs
			Control.GestureData.ScrollData sd = e.UserState as Control.GestureData.ScrollData;

			ResetInactivityTimer();// = true;

			//bool negativeX = false;
			//bool negativeY = false;

			//bool left = false, right = false, up = false, down = false;

			//if (sd.X < 0) negativeX = true;
			//if (sd.Y < 0) negativeY = true;

			//if (Math.Abs(sd.X) > Math.Abs(sd.Y))
			//{
			//    if (negativeX) left = true;
			//    else right = true;
			//}
			//else
			//{
			//    if (negativeY) up = true;
			//    else down = true;
			//}

			//// change timetables
			//if (_expanderList[_expanderIndex].Name == "eHorarios")
			//{
			//    //Logger.Instance.Write(this, "USER", "Fling: User changed Timetable");

			//    if (left) ctrlTimetables.TimeTable_Left(this, null);
			//    else if (right) ctrlTimetables.TimeTable_Right(this, null);
			//    else if (up) ctrlTimetables.TimeTable_Up(this, null);
			//    else if (down) ctrlTimetables.TimeTable_Down(this, null);

			//    return;
			///}

			// Scroll teachers
			if (_expanderList[_expanderIndex].Name == "eDocentes")
			{
				if (sd.X > sd.Y)
				{
					//Logger.Instance.Write(this, "USER", "User tried flinging left/right in teachers pane");
				}

				//Logger.Instance.Write(this, "USER", "Fling: Kinectic teachers!");
				
				ctrlTeachers.Fling(sd.X, sd.Y);
				return;
			}

			//Logger.Instance.Write(this, "USER", "Flinging in wrong pane");

		}

		#endregion

		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			//Logger.Instance.CloseFile();

			_modalWindow.Close();
			_modalWindow.Dispose();
		}
	}
}
